﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.IO;

[assembly: WebResource("EnhancedWebControls.ClientScripts.TextBoxBehavior.js", "text/javascript")]
namespace EnhancedWebControls
{
    /// <summary>
    /// Labeled Text Box Control
    /// </summary>
    [DefaultProperty("Text"), 
    ToolboxData("<{0}:EnhancedTextBox runat=server></{0}:EnhancedTextBox>"), 
    ParseChildren(true, "Text"), 
    DefaultEvent("TextChanged")]
    public class EnhancedTextBox : LabeledInput, IPostBackDataHandler, ITextControl
    {
        #region Public Enumerators
        /// <summary>
        /// Constant values that determine how to Autopostback for some labeled controls
        /// </summary>
        public enum AutoPostBackModes
        {
            Off = 1,
            Normal = 2,
            OnKeyUp = 3
        }
        #endregion

        #region Events
        public event EventHandler TextChanged;
        protected virtual void OnTextChanged(object sender, System.EventArgs e)
        {
            if (TextChanged != null)
                TextChanged(this, e);
        }
        #endregion

        #region Child Controls
        protected TextBox _rightTextBox;
        #endregion
        
        #region Private Storage
        private bool _isInUpdatePanel;
        private bool _isInUpdatePanelSet;
        #endregion
            
        #region Public Properties
        public string EmptyMessage {
            get
            {
                return Convert.ToString(ViewState["EmptyMessage"]);
            }
            set
            {
                ViewState["EmptyMessage"] = value;
            }
        }
        public int DelayMsOnKeyUp {get;set;}
        public bool IsInUpdatePanel
        {
            get 
            {
                if (!_isInUpdatePanelSet)
                {
                    _isInUpdatePanel = IsControlInAnUpdatePanel();
                    _isInUpdatePanelSet = true;
                }
                return _isInUpdatePanel;
            }
        }
        public AutoPostBackModes AutoPostBackMode { get;set;}
        protected bool IsTrigger(UpdatePanel upanel)
        {
            if (upanel.ChildrenAsTriggers)
                return true;
            else
            {
                foreach (var x in upanel.Triggers)
                {
                    if (x is AsyncPostBackTrigger)
                        if (((AsyncPostBackTrigger)x).ControlID == ID)
                            return true;
                }
            }
            return false;
        }
        #endregion
        
        #region Public Viewstate Properties
        [Category("Appearance"), DefaultValue(false), Localizable(true)]
        public bool PhoneMode
        {
            get
            {
                return Convert.ToBoolean(ViewState["phoneMode"]);
            }
            set
            {
                ViewState["phoneMode"] = value;
            }
        }
        [Category("Appearance")]
        public Unit TextAreaHeight
        {
            get
            {
                return (Unit)ViewState["TextAreaHeight"];
            }
            set
            {
                ViewState["TextAreaHeight"] = value;
            }
        }
        #endregion

        #region Exposed Child Control Properties
        public override string ToolTip
        {
            get 
            {
                EnsureChildControls();
                return base.ToolTip;
            }
            set 
            {
                EnsureChildControls();
                base.ToolTip = value;
                _rightTextBox.ToolTip = value;
            }
        }
        public AutoCompleteType AutoCompleteType
        {
            get 
            {
                EnsureChildControls();
                return _rightTextBox.AutoCompleteType;
            }
            set 
            {
                EnsureChildControls();
                _rightTextBox.AutoCompleteType = value;
            }
        }
        [Bindable(true), Category("Appearance"), DefaultValue(""), Localizable(true),PersistenceMode(PersistenceMode.InnerDefaultProperty)]
        public string Text
        {
            get 
            {
                return (string)ViewState["Text"];
            }
            set 
            {
                ViewState["Text"] = value;
            }
        }
        public TextBoxMode TextMode
        {
            get 
            {
                EnsureChildControls();
                return _rightTextBox.TextMode;
            }
            set 
            {
                EnsureChildControls();
                _rightTextBox.TextMode = value;
            }
        }
        public TextBox RightTextBox
        {
            get
            {
                EnsureChildControls();
                return _rightTextBox;
            }
        }
        #endregion
            
        #region Methods
        public EnhancedTextBox() : base()
        {
            DelayMsOnKeyUp = 300;
            TextAreaHeight = new Unit(100, UnitType.Pixel);
        }
        protected override void CreateChildControls()
        {
            Controls.Clear();
            base.CreateChildControls();

            _rightTextBox = new TextBox();
            _rightTextBox.ID = "RightTextBox";
            Controls.Add(_rightTextBox);
            _leftLabel.AssociatedControlID = _rightTextBox.ID;
        }                
        protected override void OnPreRender(System.EventArgs e)
        {
            EnsureChildControls();
            base.OnPreRender(e);
            if (this.Visible && !LabelMode)
            {
                if (Enabled)
                {
                    ScriptManager.RegisterClientScriptResource(this, this.GetType(), "EnhancedWebControls.ClientScripts.TextBoxBehavior.js");
                    SetTextBoxClientScripts();
                }
                Page.RegisterRequiresPostBack(this);
            }
        }
        protected override void Render(HtmlTextWriter writer)
        {
            EnsureChildControls();
            RenderDesignTimeStyles(writer);
            RenderContainerBegin(writer, true);
            RenderLeftSide(writer);
            RenderRightContainerBegin(writer);
            if (LabelMode)
                RenderRightLabel(writer);
            else
                RenderRightTextBox(writer, 0);
            RenderRightContainerEnd(writer);
            RenderContainerEnd(writer);
        }
        protected void RenderRightLabel(HtmlTextWriter writer)
        {
            switch (FieldAlign)
            {
                case FieldAlignment.Center:
                    _rightLabel.Style.Add("text-align", "center");
                    _rightLabel.Style.Add("margin-right", "auto");
                    _rightLabel.Style.Add("margin-left", "auto");
                    break;
                case FieldAlignment.Right:
                    _rightLabel.Style.Add("text-align", "right");
                    _rightLabel.Style.Add("float", "right");
                    break;
                default:
                    _rightLabel.Style.Add("text-align", "left");
                    _rightLabel.Style.Add("float", "left");
                    break;
            }
            _rightLabel.Text = Text;
            _rightLabel.CssClass = "EWC__LabelMode";
            _rightLabel.RenderControl(writer);
        }
        protected void RenderRightTextBox(HtmlTextWriter writer, int shrinkWidthBy)
        {
            switch (FieldAlign)
            {
                case FieldAlignment.Center:
                    _rightTextBox.Style.Add("text-align", "center");
                    break;
                case FieldAlignment.Right:
                    _rightTextBox.Style.Add("text-align", "right");
                    break;
                default:
                    _rightTextBox.Style.Add("text-align", "left");
                    break;
            }

            if (string.IsNullOrEmpty(this.Text) && !string.IsNullOrEmpty(EmptyMessage))
            {
                _rightTextBox.Text = EmptyMessage;
                if (ErrorMode)
                    _rightTextBox.CssClass = "EWC__EmptyErrorTextBox";
                else
                    _rightTextBox.CssClass = "EWC__EmptyTextBox";
            }
            else
            {
                _rightTextBox.Text = Text;
                if (ErrorMode)
                    _rightTextBox.CssClass = "EWC__ErrorTextBox";
                else
                    _rightTextBox.CssClass = "EWC__TextBox";
            }

            _rightTextBox.Style["padding-left"] = "2px";
            _rightTextBox.Style["padding-right"] = "2px";
            _rightTextBox.Style["border-width"] = "1px";
            _rightTextBox.Style["border-style"] = "solid";
            if (TextMode == TextBoxMode.MultiLine)
                _rightTextBox.Style["height"] = TextAreaHeight.ToString();
            _rightTextBox.Style["width"] = (FieldWidth.Value - (6 + shrinkWidthBy)).ToString() + "px";
            if (AutoPostBackMode == AutoPostBackModes.Normal)
                _rightTextBox.AutoPostBack = true;
            else
                _rightTextBox.AutoPostBack = false;
            _rightTextBox.RenderControl(writer);
        }
        #endregion

        #region IPostBackDataHandler Methods
        public virtual bool LoadPostData(string postDataKey, System.Collections.Specialized.NameValueCollection postCollection)
        {
            string originalValue = this.Text;
            //string newValue;
            if (LabelMode)
                this.Text = postCollection[_rightLabel.UniqueID];
            else
            {
                this.Text = postCollection[_rightTextBox.UniqueID];
                if (!string.IsNullOrEmpty(EmptyMessage))
                    if (this.Text == EmptyMessage)
                    {
                        this.Text = null;
                    }
            }

            if (string.IsNullOrEmpty(originalValue))
                originalValue = string.Empty;
            if (string.IsNullOrEmpty(this.Text))
                this.Text = string.Empty;

            if (originalValue != this.Text)
                return true;
            else
                return false;
        }
        public virtual void RaisePostDataChangedEvent()
        {
            OnTextChanged(this,new System.EventArgs());
        }
        #endregion

        #region Utility Methods
        protected bool IsControlInAnUpdatePanel()
        {
            Control currentParent = Parent;
            while (!(currentParent is Page))
            {
                if (currentParent is UpdatePanel)
                {
                    if (((UpdatePanel)currentParent).UpdateMode == UpdatePanelUpdateMode.Conditional)
                    {
                        if (IsTrigger((UpdatePanel)currentParent))
                            return true;
                    }
                    else
                        return true;
                }
                currentParent = currentParent.Parent;
            }
            return false;
        }
        protected string GetOnBlurClientScript(string overrideFieldId)
        {
            if (string.IsNullOrEmpty(overrideFieldId))
                overrideFieldId = "this";
            else
                overrideFieldId = "document.getElementById('" + overrideFieldId + "')";

            StringBuilder scriptText = new StringBuilder();
            string textBoxClass = "EWC__TextBox";
            string labelClass = "EWC__Label";
            string emptyClass = "EWC__EmptyTextBox";

            if (ErrorMode)
            {
                textBoxClass = "EWC__ErrorTextBox";
                labelClass = "EWC__ErrorLabel";
                emptyClass = "EWC__EmptyErrorTextBox";
            }
            scriptText.Append("ChangeField(" + overrideFieldId + ",\"" + textBoxClass + "\",\"" + _leftLabel.ClientID + "\",\"" + labelClass + "\");");
            if (PhoneMode)
                scriptText.Append("BlurPhone(" + overrideFieldId + ");");

            if (!string.IsNullOrEmpty(EmptyMessage))
                scriptText.Append("ShowEmptyMessage(" + overrideFieldId + "," + EmptyMessage.EncodeJsString() + ",\"" + emptyClass + "\");");

            return scriptText.ToString();
        }
        protected string GetOnFocusClientScript(string overrideFieldId)
        {
            if (string.IsNullOrEmpty(overrideFieldId))
                overrideFieldId = "this";
            else
                overrideFieldId = "document.getElementById(\"" + overrideFieldId + "\")";
            StringBuilder scriptText = new StringBuilder();
            scriptText.Append("ChangeField(" + overrideFieldId + ",\"EWC__ActiveTextBox\",\"" + _leftLabel.ClientID + "\",\"EWC__ActiveLabel\");");

            if (!string.IsNullOrEmpty(EmptyMessage))
                scriptText.Append("HideEmptyMessage(" + overrideFieldId + "," + EmptyMessage.EncodeJsString() + ",\"EWC__ActiveTextBox\");");

            return scriptText.ToString();
        }
        protected string GetOnKeyDownClientScript()
        {
            StringBuilder scriptText = new StringBuilder();        
            if (PhoneMode)
                scriptText.Append("return FormatPhone(this,event);");

            return scriptText.ToString();
        }
        protected string GetOnKeyUpClientScript()
        {
            StringBuilder scriptText = new StringBuilder();
            if (AutoPostBackMode == AutoPostBackModes.OnKeyUp)
            {
                if (!IsInUpdatePanel)
                    scriptText.Append("RaiseOnKeyUpEvent");
                else
                    throw new NotSupportedException(
                        "You cannot use the OnKeyUp AutoPostBackMode if the EnhancedTextBox is inside an UpdatePanel " +
                        "that will be refreshed on the AutoPostBack event. If the EnhancedTextBox must be in an UpdatePanel " +
                        "use a seperate UpdatePanel for the EnhancedTextBox with the settings UpdateMode = Conditional " + 
                        "and ChildrenAsTriggers = False. This will eliminate the refresh when the AutoPostBack event is fired.");

                if (string.IsNullOrEmpty(EmptyMessage))
                    scriptText.Append("(this,null," + DelayMsOnKeyUp.ToString() + ");");
                else
                    scriptText.Append("(this," + EmptyMessage.EncodeJsString() + "," + DelayMsOnKeyUp.ToString() + ");");
            }
            return scriptText.ToString();
        }
        protected void SetTextBoxClientScripts()
        {
            string blurText = GetOnBlurClientScript(null);
            string focusText = GetOnFocusClientScript(null);
            string keyUpText = GetOnKeyUpClientScript();
            string keyDownText = GetOnKeyDownClientScript();

            if (!string.IsNullOrEmpty(blurText))
                _rightTextBox.Attributes.Add("onblur", blurText);
            if (!string.IsNullOrEmpty(focusText))
                _rightTextBox.Attributes.Add("onfocus", focusText);
            if (!string.IsNullOrEmpty(keyUpText))
                _rightTextBox.Attributes.Add("onkeyup", keyUpText);
            if (!string.IsNullOrEmpty(keyDownText))
                _rightTextBox.Attributes.Add("onkeydown", keyDownText);
        }
        #endregion
    }
}